Popular Searches
Popular Course Categories
Popular Courses

Build a Flutter News App Using API

Build a Flutter News App Using API

Flutter Practical Projects

Build a Flutter News App Using API

Building a Flutter News App Using API is a practical project that demonstrates how Flutter applications communicate with external web services to retrieve and display real-time or frequently updated news data. In this project, we will build a complete news application where users can browse headlines, filter news by categories, search for articles, open article details, refresh content, and handle loading and error states.

This project combines Flutter UI development, Dart programming, HTTP requests, JSON parsing, API integration, asynchronous programming, reusable widgets, navigation, search, filtering, responsive design, and clean application architecture.


1. Project Objectives

The main objective of this project is to understand how to build a Flutter application that consumes data from a REST API.

  • Create a modern Flutter news application.
  • Understand REST API concepts.
  • Send HTTP requests from Flutter.
  • Parse JSON responses.
  • Convert JSON data into Dart models.
  • Display news articles dynamically.
  • Implement category-based news filtering.
  • Implement news search.
  • Open detailed news information.
  • Handle loading states.
  • Handle API errors.
  • Implement pull-to-refresh.
  • Create reusable news widgets.
  • Build a responsive news interface.
  • Organize API-related code using services.

2. What We Will Build

The application will contain multiple screens and reusable components.

Screen / ComponentPurpose
Splash ScreenDisplays application branding when the application starts.
Home ScreenDisplays the latest news articles.
Category ScreenDisplays news from a selected category.
Search ScreenAllows users to search for news.
News Detail ScreenDisplays detailed information about an article.
Bookmark ScreenDisplays saved articles.
Profile / SettingsContains application preferences.

3. Technologies Used

TechnologyPurpose
FlutterBuilds the cross-platform mobile application.
DartProgramming language used by Flutter.
REST APIProvides news data.
HTTP PackageSends HTTP requests to the API.
JSONRepresents API response data.
Material DesignProvides Flutter UI components.
Provider / Riverpod / BlocCan be used for application state management.

4. Prerequisites

Before starting this project, you should understand basic Flutter and Dart concepts.

  • Dart variables and data types.
  • Functions.
  • Classes and objects.
  • Constructors.
  • Lists and maps.
  • Future and async/await.
  • Flutter widgets.
  • StatelessWidget and StatefulWidget.
  • Row and Column.
  • ListView and GridView.
  • Navigation.
  • Basic exception handling.

5. Understanding APIs

API stands for Application Programming Interface. A web API allows one application to communicate with another application or server.

In a news application, the Flutter application sends a request to a news API. The API processes the request and returns news data, usually in JSON format.

6. Basic API Flow

Flutter Application
       |
       | HTTP Request
       v
    News API
       |
       | JSON Response
       v
Flutter Application
       |
       v
Parse JSON
       |
       v
Create Dart Models
       |
       v
Display News UI

7. Common HTTP Methods

MethodPurpose
GETRetrieve data from a server.
POSTSend new data to a server.
PUTUpdate existing data.
PATCHPartially update existing data.
DELETEDelete data from a server.

For a news application, the most common operation is a GET request because the application primarily retrieves news articles.

8. Create the Flutter Project

flutter create news_app

Move into the project directory:

cd news_app

Run the project:

flutter run

9. Add the HTTP Package

We can use the HTTP package to communicate with a REST API.

flutter pub add http

After adding the package, import it in the API service:

import 'package:http/http.dart' as http;

10. Recommended Project Structure

lib/
├── main.dart
├── app.dart
├── models/
│   └── news_article.dart
├── services/
│   └── news_api_service.dart
├── screens/
│   ├── splash_screen.dart
│   ├── home_screen.dart
│   ├── category_screen.dart
│   ├── search_screen.dart
│   ├── news_detail_screen.dart
│   └── bookmarks_screen.dart
├── widgets/
│   ├── news_card.dart
│   ├── category_chip.dart
│   ├── featured_news_card.dart
│   ├── loading_widget.dart
│   └── error_widget.dart
├── providers/
│   └── news_provider.dart
└── utils/
    ├── app_colors.dart
    ├── app_constants.dart
    └── api_constants.dart

11. Create the Main Entry Point

import 'package:flutter/material.dart';
import 'app.dart';

void main() {
  runApp(const NewsApp());
}

12. Create the Main Application

import 'package:flutter/material.dart';
import 'screens/splash_screen.dart';

class NewsApp extends StatelessWidget {
  const NewsApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'News App',
      theme: ThemeData(
        useMaterial3: true,
        colorSchemeSeed: Colors.blue,
      ),
      home: const SplashScreen(),
    );
  }
}

13. API Endpoint Concept

A typical news API request may contain parameters such as country, category, search keyword, language, page number, or API key.

https://example-news-api.com/v1/top-headlines
    ?country=in
    &category=technology
    &apiKey=YOUR_API_KEY

The exact endpoint and parameters depend on the news API provider being used.

14. API Constants

Keep API configuration values in a separate constants file.

class ApiConstants {
  static const String baseUrl =
      'https://example-news-api.com';

  static const String apiKey =
      'YOUR_API_KEY';

  static const String topHeadlines =
      '/v1/top-headlines';
}

For production applications, sensitive credentials should be handled using an appropriate secure configuration strategy rather than exposing them unnecessarily in source code.

15. Understanding JSON

Most REST APIs return data in JSON format.

A simplified news API response may look like this:

{
  "status": "ok",
  "totalResults": 2,
  "articles": [
    {
      "title": "Flutter News Application",
      "description": "A practical Flutter application.",
      "url": "https://example.com/article",
      "urlToImage": "https://example.com/image.jpg",
      "publishedAt": "2026-09-22T10:00:00Z",
      "source": {
        "name": "Example News"
      }
    }
  ]
}

16. JSON Structure

The response normally contains a top-level object and an array of article objects.

Response
   |
   +-- status
   |
   +-- totalResults
   |
   +-- articles
          |
          +-- article 1
          +-- article 2
          +-- article 3
          +-- article 4

17. Create News Article Model

Instead of working directly with raw JSON throughout the application, create a Dart model.

class NewsArticle {
  final String title;
  final String description;
  final String imageUrl;
  final String articleUrl;
  final String sourceName;
  final DateTime? publishedAt;

  NewsArticle({
    required this.title,
    required this.description,
    required this.imageUrl,
    required this.articleUrl,
    required this.sourceName,
    required this.publishedAt,
  });
}

18. Create fromJson Factory

A factory constructor can convert a JSON object into a Dart model.

class NewsArticle {
  final String title;
  final String description;
  final String imageUrl;
  final String articleUrl;
  final String sourceName;
  final DateTime? publishedAt;

  NewsArticle({
    required this.title,
    required this.description,
    required this.imageUrl,
    required this.articleUrl,
    required this.sourceName,
    required this.publishedAt,
  });

  factory NewsArticle.fromJson(
    Map<String, dynamic> json,
  ) {
    return NewsArticle(
      title: json['title'] ?? 'No Title',
      description: json['description'] ?? '',
      imageUrl: json['urlToImage'] ?? '',
      articleUrl: json['url'] ?? '',
      sourceName: json['source']?['name'] ?? 'Unknown',
      publishedAt: json['publishedAt'] != null
          ? DateTime.tryParse(
              json['publishedAt'],
            )
          : null,
    );
  }
}

19. Why Use Models?

  • Improves code readability.
  • Provides structured data.
  • Reduces repeated JSON access.
  • Makes widgets easier to understand.
  • Improves type safety.
  • Makes API changes easier to manage.

20. Create the News API Service

The API service is responsible for communicating with the remote news server.

import 'dart:convert';
import 'package:http/http.dart' as http;

class NewsApiService {
  final String baseUrl =
      'https://example-news-api.com';

  final String apiKey = 'YOUR_API_KEY';

  Future<List<NewsArticle>> fetchTopHeadlines() async {
    final uri = Uri.parse(
      '$baseUrl/v1/top-headlines'
      '?country=in'
      '&apiKey=$apiKey',
    );

    final response = await http.get(uri);

    if (response.statusCode == 200) {
      final data = jsonDecode(response.body);

      final articles = data['articles'] as List;

      return articles
          .map(
            (article) =>
                NewsArticle.fromJson(article),
          )
          .toList();
    }

    throw Exception(
      'Failed to load news',
    );
  }
}

21. Understanding async and await

API requests take time because the application needs to communicate with a remote server. Dart uses asynchronous programming to prevent the UI from freezing while waiting for the response.

Future<List<NewsArticle>> fetchNews() async {
  final response = await http.get(uri);
  return parseNews(response.body);
}

22. Future in Dart

A Future represents a value that will be available at some point in the future.

Future<String> getNews() async {
  return 'News loaded';
}

23. API Status Codes

Status CodeMeaning
200Request succeeded.
201Resource created successfully.
400Bad request.
401Authentication or API key problem.
403Access forbidden.
404Resource not found.
429Too many requests.
500Server error.

24. Handle API Errors

try {
  final articles =
      await newsApiService.fetchTopHeadlines();
} catch (e) {
  debugPrint(
    'News API Error: $e',
  );
}

25. Create the Splash Screen

import 'package:flutter/material.dart';
import 'home_screen.dart';

class SplashScreen extends StatefulWidget {
  const SplashScreen({super.key});

  @override
  State<SplashScreen> createState() =>
      _SplashScreenState();
}

class _SplashScreenState
    extends State<SplashScreen> {

  @override
  void initState() {
    super.initState();

    Future.delayed(
      const Duration(seconds: 2),
      () {
        if (!mounted) return;

        Navigator.pushReplacement(
          context,
          MaterialPageRoute(
            builder: (_) =>
                const HomeScreen(),
          ),
        );
      },
    );
  }

  @override
  Widget build(BuildContext context) {
    return const Scaffold(
      body: Center(
        child: Text(
          'NEWS',
          style: TextStyle(
            fontSize: 36,
            fontWeight: FontWeight.bold,
          ),
        ),
      ),
    );
  }
}

26. Home Screen

The home screen is the main screen where users discover news articles.

A typical home screen can contain:

  • Application logo or title.
  • Search bar.
  • Breaking news section.
  • Category list.
  • Latest news section.
  • Featured news.
  • News cards.
  • Bottom navigation.

27. Home Screen with FutureBuilder

FutureBuilder can be used when news is loaded from a Future.

class HomeScreen extends StatelessWidget {
  const HomeScreen({super.key});

  @override
  Widget build(BuildContext context) {
    final service = NewsApiService();

    return Scaffold(
      appBar: AppBar(
        title: const Text('Latest News'),
      ),
      body: FutureBuilder<List<NewsArticle>>(
        future: service.fetchTopHeadlines(),
        builder: (
          context,
          snapshot,
        ) {
          if (snapshot.connectionState ==
              ConnectionState.waiting) {
            return const Center(
              child: CircularProgressIndicator(),
            );
          }

          if (snapshot.hasError) {
            return Center(
              child: Text(
                'Error: ${snapshot.error}',
              ),
            );
          }

          final articles =
              snapshot.data ?? [];

          if (articles.isEmpty) {
            return const Center(
              child: Text(
                'No news available',
              ),
            );
          }

          return ListView.builder(
            itemCount: articles.length,
            itemBuilder: (
              context,
              index,
            ) {
              return NewsCard(
                article: articles[index],
              );
            },
          );
        },
      ),
    );
  }
}

28. FutureBuilder States

FutureBuilder can represent several states.

Loading
   |
   v
API Request
   |
   +------> Success ------> Display News
   |
   +------> Error --------> Display Error
   |
   +------> Empty --------> Display Empty State

29. Create News Card

A reusable news card can display the image, title, source, date, and description.

class NewsCard extends StatelessWidget {
  final NewsArticle article;

  const NewsCard({
    super.key,
    required this.article,
  });

  @override
  Widget build(BuildContext context) {
    return Card(
      margin: const EdgeInsets.all(12),
      clipBehavior: Clip.antiAlias,
      child: Column(
        crossAxisAlignment:
            CrossAxisAlignment.start,
        children: [
          if (article.imageUrl.isNotEmpty)
            Image.network(
              article.imageUrl,
              height: 200,
              width: double.infinity,
              fit: BoxFit.cover,
              errorBuilder: (
                context,
                error,
                stackTrace,
              ) {
                return const SizedBox(
                  height: 200,
                  child: Center(
                    child: Icon(
                      Icons.image_not_supported,
                    ),
                  ),
                );
              },
            ),
          Padding(
            padding: const EdgeInsets.all(14),
            child: Column(
              crossAxisAlignment:
                  CrossAxisAlignment.start,
              children: [
                Text(
                  article.sourceName,
                  style: const TextStyle(
                    fontWeight: FontWeight.bold,
                  ),
                ),
                const SizedBox(height: 8),
                Text(
                  article.title,
                  style: const TextStyle(
                    fontSize: 18,
                    fontWeight: FontWeight.bold,
                  ),
                ),
                const SizedBox(height: 8),
                Text(
                  article.description,
                  maxLines: 3,
                  overflow:
                      TextOverflow.ellipsis,
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}

30. News Card Information

ElementPurpose
ImageProvides visual representation of the article.
SourceDisplays the news publisher.
TitleDisplays the main headline.
DescriptionProvides a short summary.
DateDisplays publication information.

31. News Detail Screen

When a user taps a news card, the application can open a detail screen.

Navigator.push(
  context,
  MaterialPageRoute(
    builder: (_) =>
        NewsDetailScreen(
      article: article,
    ),
  ),
);

32. Create News Detail Screen

class NewsDetailScreen extends StatelessWidget {
  final NewsArticle article;

  const NewsDetailScreen({
    super.key,
    required this.article,
  });

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('News Details'),
      ),
      body: SingleChildScrollView(
        child: Column(
          crossAxisAlignment:
              CrossAxisAlignment.start,
          children: [
            if (article.imageUrl.isNotEmpty)
              Image.network(
                article.imageUrl,
                height: 260,
                width: double.infinity,
                fit: BoxFit.cover,
              ),
            Padding(
              padding: const EdgeInsets.all(20),
              child: Column(
                crossAxisAlignment:
                    CrossAxisAlignment.start,
                children: [
                  Text(
                    article.sourceName,
                    style: const TextStyle(
                      fontWeight: FontWeight.bold,
                    ),
                  ),
                  const SizedBox(height: 10),
                  Text(
                    article.title,
                    style: const TextStyle(
                      fontSize: 26,
                      fontWeight: FontWeight.bold,
                    ),
                  ),
                  const SizedBox(height: 16),
                  Text(
                    article.description,
                    style: const TextStyle(
                      fontSize: 17,
                    ),
                  ),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }
}

33. Opening the Original Article

A news application can provide a button that opens the original article URL in a browser or supported web-view experience.

For this feature, a URL-launching package can be used.

final uri = Uri.parse(
  article.articleUrl,
);

34. News Categories

Categories help users quickly find news relevant to their interests.

CategoryExample Content
GeneralGeneral current events.
BusinessBusiness and finance news.
TechnologyTechnology and software news.
SportsSports-related news.
EntertainmentEntertainment and media news.
HealthHealth-related news.
ScienceScience and research news.

35. Category Chip Widget

class CategoryChip extends StatelessWidget {
  final String title;
  final VoidCallback onTap;

  const CategoryChip({
    super.key,
    required this.title,
    required this.onTap,
  });

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.only(
        right: 8,
      ),
      child: ActionChip(
        label: Text(title),
        onPressed: onTap,
      ),
    );
  }
}

36. Category API Request

A news API may support category parameters.

GET /v1/top-headlines
    ?country=in
    &category=technology
    &apiKey=YOUR_API_KEY

37. Fetch News by Category

Future<List<NewsArticle>> fetchByCategory(
  String category,
) async {
  final uri = Uri.parse(
    '$baseUrl/v1/top-headlines'
    '?country=in'
    '&category=$category'
    '&apiKey=$apiKey',
  );

  final response =
      await http.get(uri);

  if (response.statusCode != 200) {
    throw Exception(
      'Unable to load category news',
    );
  }

  final data =
      jsonDecode(response.body);

  final articles =
      data['articles'] as List;

  return articles
      .map(
        (article) =>
            NewsArticle.fromJson(article),
      )
      .toList();
}

38. Search News

Search functionality allows users to find articles based on keywords.

Future<List<NewsArticle>> searchNews(
  String query,
) async {
  final uri = Uri.parse(
    '$baseUrl/v2/everything'
    '?q=${Uri.encodeQueryComponent(query)}'
    '&apiKey=$apiKey',
  );

  final response =
      await http.get(uri);

  if (response.statusCode != 200) {
    throw Exception(
      'Search request failed',
    );
  }

  final data =
      jsonDecode(response.body);

  final articles =
      data['articles'] as List;

  return articles
      .map(
        (article) =>
            NewsArticle.fromJson(article),
      )
      .toList();
}

39. Search Screen

The search screen can contain a text field and a dynamically updated list of matching articles.

TextField(
  controller: searchController,
  textInputAction:
      TextInputAction.search,
  decoration: InputDecoration(
    hintText: 'Search news',
    prefixIcon: const Icon(
      Icons.search,
    ),
    suffixIcon: IconButton(
      onPressed: () {},
      icon: const Icon(
        Icons.arrow_forward,
      ),
    ),
  ),
)

40. Search Flow

User enters keyword
        |
        v
Search Button
        |
        v
Create API Request
        |
        v
Send HTTP GET
        |
        v
Receive JSON
        |
        v
Parse Articles
        |
        v
Display Search Results

41. Pull-to-Refresh

Users should be able to refresh the latest news by pulling the list downward.

RefreshIndicator(
  onRefresh: () async {
    await loadNews();
  },
  child: ListView.builder(
    itemCount: articles.length,
    itemBuilder: (
      context,
      index,
    ) {
      return NewsCard(
        article: articles[index],
      );
    },
  ),
)

42. Loading Indicator

A loading indicator should be displayed while the API request is in progress.

const Center(
  child: CircularProgressIndicator(),
)

43. Error State

When an API request fails, the user should receive a meaningful error message and preferably a retry action.

Center(
  child: Column(
    mainAxisAlignment:
        MainAxisAlignment.center,
    children: [
      const Text(
        'Unable to load news.',
      ),
      const SizedBox(height: 12),
      ElevatedButton(
        onPressed: () {},
        child: const Text(
          'Retry',
        ),
      ),
    ],
  ),
)

44. Empty State

An empty state should be shown when the API successfully responds but does not contain articles.

if (articles.isEmpty) {
  return const Center(
    child: Text(
      'No news articles found.',
    ),
  );
}

45. Network Error Handling

Network requests can fail because of connectivity problems, server errors, invalid URLs, API limits, or authentication issues.

try {
  final articles =
      await newsApiService
          .fetchTopHeadlines();
} catch (e) {
  debugPrint(
    'Request failed: $e',
  );
}

46. Connection Timeout

Applications should avoid waiting indefinitely for a remote server.

final response = await http
    .get(uri)
    .timeout(
      const Duration(
        seconds: 15,
      ),
    );

47. Handling Invalid JSON

An API response may sometimes have an unexpected structure. JSON parsing should therefore be handled carefully.

try {
  final data =
      jsonDecode(response.body);

  if (data['articles'] is! List) {
    throw Exception(
      'Invalid article response',
    );
  }
} catch (e) {
  debugPrint(
    'JSON parsing error: $e',
  );
}

48. Safe Image Loading

Some news articles may not contain an image. The UI should handle missing or invalid image URLs.

if (article.imageUrl.isEmpty)
  const SizedBox(
    height: 200,
    child: Center(
      child: Icon(
        Icons.image,
        size: 60,
      ),
    ),
  )
else
  Image.network(
    article.imageUrl,
    height: 200,
    width: double.infinity,
    fit: BoxFit.cover,
  )

49. Date Formatting

News APIs commonly return dates in ISO 8601 format. The application can convert them into a user-friendly format.

String formatDate(
  DateTime? date,
) {
  if (date == null) {
    return 'Unknown date';
  }

  return '${date.day}/'
      '${date.month}/'
      '${date.year}';
}

50. Relative Date Display

A more advanced application can display values such as:

  • 5 minutes ago.
  • 2 hours ago.
  • Yesterday.
  • 3 days ago.

This improves readability for frequently updated news content.

51. Featured News

A featured news section can highlight important articles at the top of the home screen.

class FeaturedNewsCard
    extends StatelessWidget {
  final NewsArticle article;

  const FeaturedNewsCard({
    super.key,
    required this.article,
  });

  @override
  Widget build(
    BuildContext context,
  ) {
    return Stack(
      children: [
        ClipRRect(
          borderRadius:
              BorderRadius.circular(16),
          child: Image.network(
            article.imageUrl,
            height: 240,
            width: double.infinity,
            fit: BoxFit.cover,
          ),
        ),
        Positioned(
          left: 16,
          right: 16,
          bottom: 16,
          child: Text(
            article.title,
            style: const TextStyle(
              color: Colors.white,
              fontSize: 20,
              fontWeight:
                  FontWeight.bold,
            ),
          ),
        ),
      ],
    );
  }
}

52. Bookmark Feature

A news application can allow users to save articles for later reading.

A simple local bookmark implementation can maintain a collection of article IDs or article objects.

final List<NewsArticle> bookmarks = [];

void addBookmark(
  NewsArticle article,
) {
  bookmarks.add(article);
}

void removeBookmark(
  NewsArticle article,
) {
  bookmarks.remove(article);
}

53. Bookmark Screen

The bookmark screen displays articles saved by the user.

  • Saved article image.
  • Article title.
  • Source name.
  • Publication date.
  • Remove bookmark action.

54. Persisting Bookmarks

For a more complete application, bookmarks can be persisted using local storage or a cloud database.

Possible approaches include:

  • SharedPreferences for simple preferences.
  • Hive for local structured data.
  • SQLite for relational local data.
  • Cloud Firestore for synchronized user bookmarks.

55. Bottom Navigation

Bottom navigation can provide access to the main areas of the application.

TabPurpose
HomeDisplays latest and featured news.
CategoriesAllows category-based browsing.
SearchSearches for articles.
BookmarksDisplays saved articles.
SettingsContains application preferences.

56. Bottom Navigation Example

NavigationBar(
  selectedIndex: currentIndex,
  onDestinationSelected: (index) {
    setState(() {
      currentIndex = index;
    });
  },
  destinations: const [
    NavigationDestination(
      icon: Icon(Icons.home_outlined),
      selectedIcon: Icon(Icons.home),
      label: 'Home',
    ),
    NavigationDestination(
      icon: Icon(Icons.category_outlined),
      selectedIcon: Icon(Icons.category),
      label: 'Categories',
    ),
    NavigationDestination(
      icon: Icon(Icons.search),
      label: 'Search',
    ),
    NavigationDestination(
      icon: Icon(Icons.bookmark_outline),
      selectedIcon: Icon(Icons.bookmark),
      label: 'Saved',
    ),
  ],
)

57. State Management

For a simple application, StatefulWidget and FutureBuilder may be enough. As the application grows, state management can make data flow easier to maintain.

Possible solutions include:

  • Provider.
  • Riverpod.
  • Bloc / Cubit.
  • ChangeNotifier.
  • ValueNotifier.

58. News Provider Example

class NewsProvider
    extends ChangeNotifier {

  final NewsApiService service =
      NewsApiService();

  List<NewsArticle> articles = [];

  bool isLoading = false;
  String? error;

  Future<void> loadNews() async {
    isLoading = true;
    error = null;
    notifyListeners();

    try {
      articles =
          await service
              .fetchTopHeadlines();
    } catch (e) {
      error =
          'Unable to load news';
    }

    isLoading = false;
    notifyListeners();
  }
}

59. Provider Data Flow

UI
 |
 v
News Provider
 |
 v
News API Service
 |
 v
HTTP Request
 |
 v
News API
 |
 v
JSON Response
 |
 v
News Model
 |
 v
Provider State
 |
 v
UI Rebuild

60. Search Debouncing

When implementing live search, sending an API request after every keystroke can create unnecessary requests. Debouncing waits for the user to stop typing before sending the request.

Timer? searchTimer;

void onSearchChanged(
  String value,
) {
  searchTimer?.cancel();

  searchTimer = Timer(
    const Duration(
      milliseconds: 500,
    ),
    () {
      if (value.trim().isNotEmpty) {
        searchNews(value);
      }
    },
  );
}

61. Pagination

Some APIs provide a large number of articles. Loading everything at once may be inefficient. Pagination allows articles to be loaded page by page.

GET /v2/everything
    ?q=flutter
    &page=1
    &pageSize=20
    &apiKey=YOUR_API_KEY

62. Pagination Flow

Load Page 1
    |
    v
Display Articles
    |
    v
User Scrolls
    |
    v
Near Bottom?
    |
   Yes
    |
    v
Load Page 2
    |
    v
Append New Articles
    |
    v
Continue...

63. Avoid Duplicate Articles

When loading multiple pages, duplicate articles can sometimes appear. Use a unique identifier such as article URL when available.

final existingUrls =
    articles
        .map(
          (article) =>
              article.articleUrl,
        )
        .toSet();

final newArticles =
    fetchedArticles.where(
  (article) =>
      !existingUrls.contains(
        article.articleUrl,
      ),
);

64. Responsive Design

The application should provide a good experience on different screen sizes.

Flutter responsive tools include:

  • MediaQuery.
  • LayoutBuilder.
  • Expanded.
  • Flexible.
  • GridView.
  • OrientationBuilder.

65. Responsive News Grid

final width =
    MediaQuery.of(context).size.width;

int columns;

if (width > 1200) {
  columns = 4;
} else if (width > 800) {
  columns = 3;
} else if (width > 500) {
  columns = 2;
} else {
  columns = 1;
}

66. Mobile News Layout

On smaller screens, a single-column layout is usually easier to read.

ListView.builder(
  itemCount: articles.length,
  itemBuilder: (
    context,
    index,
  ) {
    return NewsCard(
      article: articles[index],
    );
  },
)

67. Tablet and Desktop Layout

On larger screens, the application can display multiple news cards in a grid.

GridView.builder(
  gridDelegate:
      SliverGridDelegateWithFixedCrossAxisCount(
    crossAxisCount: 3,
    crossAxisSpacing: 16,
    mainAxisSpacing: 16,
    childAspectRatio: 0.8,
  ),
  itemCount: articles.length,
  itemBuilder: (
    context,
    index,
  ) {
    return NewsCard(
      article: articles[index],
    );
  },
)

68. Theme Configuration

ThemeData(
  useMaterial3: true,
  colorSchemeSeed: Colors.blue,
  scaffoldBackgroundColor:
      Colors.white,
  appBarTheme: const AppBarTheme(
    centerTitle: true,
  ),
)

69. Application Colors

class AppColors {
  static const primary =
      Colors.blue;

  static const background =
      Color(0xFFF7F8FA);

  static const textPrimary =
      Color(0xFF202124);

  static const textSecondary =
      Color(0xFF6B7280);

  static const error =
      Colors.red;
}

70. Search Filtering Locally

If articles have already been loaded, simple filtering can be performed locally.

List<NewsArticle> filterArticles(
  List<NewsArticle> articles,
  String query,
) {
  return articles.where(
    (article) {
      final title =
          article.title.toLowerCase();

      return title.contains(
        query.toLowerCase(),
      );
    },
  ).toList();
}

71. Share News

A useful feature is allowing users to share an article URL with other applications.

A sharing package can be used to implement this functionality.

final shareText =
    '${article.title}\n'
    '${article.articleUrl}';

72. Open External Article

The original article URL can be opened using a suitable URL-launching package.

final uri = Uri.parse(
  article.articleUrl,
);

The application should also verify that the URL can be launched successfully before attempting to open it.

73. API Key Management

Many news APIs require an API key. The key should not be treated as ordinary public data.

  • Do not commit secrets to public repositories.
  • Use environment-specific configuration where appropriate.
  • Use backend mediation when the API provider requires stronger protection.
  • Restrict API keys when the provider supports restrictions.
  • Rotate compromised keys.

74. API Rate Limits

News APIs may restrict how many requests an application can make within a particular period.

To reduce unnecessary requests:

  • Use caching where appropriate.
  • Debounce search requests.
  • Avoid repeated API calls during rebuilds.
  • Use pagination.
  • Refresh only when needed.
  • Handle HTTP 429 responses gracefully.

75. Caching News Data

For a better user experience, previously loaded news can be cached locally. This can allow the application to show recent data even when the network is temporarily unavailable.

Possible storage solutions include:

  • SharedPreferences for simple data.
  • Hive.
  • SQLite.
  • Drift.

76. Offline Experience

A more advanced news application can use the following strategy:

Open App
   |
   v
Check Local Cache
   |
   +----> Cached Articles Available
   |              |
   |              v
   |        Display Cached News
   |
   v
Request Fresh API Data
   |
   +----> Success
   |       |
   |       v
   |   Update Cache
   |
   +----> Failure
           |
           v
     Keep Cached News

77. Loading Skeleton

Instead of displaying only a circular progress indicator, a production-style application can display skeleton placeholders that resemble the final news cards.

Column(
  children: [
    Container(
      height: 200,
      width: double.infinity,
      decoration: BoxDecoration(
        color: Colors.grey.shade300,
        borderRadius:
            BorderRadius.circular(12),
      ),
    ),
    const SizedBox(height: 12),
    Container(
      height: 20,
      width: double.infinity,
      color: Colors.grey,
    ),
    const SizedBox(height: 8),
    Container(
      height: 16,
      width: 200,
      color: Colors.grey,
    ),
  ],
)

78. Accessibility

The news application should also consider accessibility.

  • Use readable font sizes.
  • Maintain sufficient contrast.
  • Provide semantic labels where useful.
  • Do not depend only on color to communicate information.
  • Make buttons large enough to interact with comfortably.
  • Support text scaling where practical.

79. Performance Optimization

  • Use const constructors wherever possible.
  • Use ListView.builder for long lists.
  • Use GridView.builder for large grids.
  • Avoid unnecessary API calls.
  • Cache images appropriately.
  • Use pagination for large datasets.
  • Avoid expensive operations inside build().
  • Dispose controllers and timers.
  • Keep business logic outside UI widgets.

80. Common Mistakes

  1. Making API calls directly inside build() without proper control.
  2. Not handling API errors.
  3. Not checking HTTP status codes.
  4. Assuming every article has an image.
  5. Assuming every JSON field is non-null.
  6. Exposing API keys unnecessarily.
  7. Sending an API request on every search keystroke.
  8. Loading too many articles at once.
  9. Not handling empty API results.
  10. Not providing a retry option.
  11. Not disposing TextEditingController and Timer.
  12. Keeping API logic mixed with UI code.

81. Best Practices

  • Create separate API service classes.
  • Create strongly typed Dart models.
  • Keep API constants centralized.
  • Handle null values safely.
  • Handle loading, success, error, and empty states.
  • Use reusable widgets.
  • Use state management as the project grows.
  • Use pagination for large datasets.
  • Use caching when appropriate.
  • Protect API credentials.
  • Provide useful error messages.
  • Test API services separately from UI.

82. Testing API Integration

The API integration should be tested under different conditions.

Test CaseExpected Result
Successful API requestNews articles are displayed.
Invalid API keyAuthentication error is handled.
No InternetNetwork error is displayed.
Empty responseEmpty state is displayed.
Invalid JSONParsing error is handled.
Missing imagePlaceholder is displayed.
Search queryRelevant articles are displayed.
Category selectionCategory-specific articles are displayed.
RefreshLatest data is requested.

83. Unit Testing API Service

API services should ideally be designed so that their logic can be tested independently from the UI.

void main() {
  test(
    'NewsArticle should parse JSON',
    () {
      final json = {
        'title': 'Test News',
        'description':
            'Test description',
        'url': 'https://example.com',
        'urlToImage': '',
        'publishedAt':
            '2026-09-22T10:00:00Z',
        'source': {
          'name': 'Test Source',
        },
      };

      final article =
          NewsArticle.fromJson(json);

      expect(
        article.title,
        'Test News',
      );
    },
  );
}

84. Debugging the API

During development, inspect the HTTP status code and response body.

debugPrint(
  'Status: ${response.statusCode}',
);

debugPrint(
  'Body: ${response.body}',
);

Do not leave sensitive API keys or excessive response logging in production builds.

85. Application Flow

Application Start
       |
       v
Splash Screen
       |
       v
Home Screen
       |
       +----------------+
       |                |
       v                v
Latest News        Categories
       |                |
       +--------+-------+
                |
                v
           News List
                |
                v
         Select Article
                |
                v
         News Detail
                |
        +-------+-------+
        |               |
        v               v
     Bookmark         Share
        |
        v
    Saved News

86. Complete API Architecture

Flutter UI
    |
    v
State Management
    |
    v
News API Service
    |
    v
HTTP Client
    |
    v
REST API
    |
    v
JSON Response
    |
    v
JSON Parser
    |
    v
News Model
    |
    v
Application State
    |
    v
Flutter UI

87. Advanced Features

After completing the basic news application, the following features can be added:

  • Dark mode.
  • Multiple languages.
  • Personalized news.
  • Push notifications.
  • Breaking news alerts.
  • Bookmarks synchronization.
  • Reading history.
  • Trending news.
  • Recommended articles.
  • Infinite scrolling.
  • Offline reading.
  • Text-to-speech.
  • News source selection.
  • Advanced filtering.

88. Dark Mode

A news application can provide light and dark themes.

MaterialApp(
  theme: ThemeData.light(
    useMaterial3: true,
  ),
  darkTheme: ThemeData.dark(
    useMaterial3: true,
  ),
  themeMode: ThemeMode.system,
)

89. Multiple Language Support

Flutter localization can be used to support multiple languages.

Possible application languages include:

  • English.
  • Hindi.
  • Spanish.
  • French.
  • German.
  • Other languages supported by the application and API.

90. Push Notifications

Push notifications can notify users when important news becomes available.

Possible notification types include:

  • Breaking news.
  • Category updates.
  • Personalized recommendations.
  • Saved-topic updates.

91. News Recommendation Flow

User Reads Articles
       |
       v
Track Selected Categories
       |
       v
Analyze User Preferences
       |
       v
Request Relevant News
       |
       v
Display Recommended Articles

92. Production Architecture

A larger application can separate responsibilities into multiple layers.

Presentation Layer
    |
    +-- Screens
    +-- Widgets
    +-- Providers / Cubits
    |
    v
Domain Layer
    |
    +-- Entities
    +-- Use Cases
    +-- Repository Contracts
    |
    v
Data Layer
    |
    +-- API Models
    +-- API Services
    +-- Repository Implementations
    +-- Local Cache

93. Repository Pattern

The repository pattern can separate the application from the specific API implementation.

UI
 |
 v
News Repository
 |
 +----> Remote API
 |
 +----> Local Cache
 |
 v
News Data

94. Why Repository Pattern Is Useful

  • Separates UI from data sources.
  • Makes testing easier.
  • Allows API implementation to change.
  • Allows local caching to be introduced.
  • Improves maintainability.

95. News API Service Responsibilities

The API service should ideally be responsible for network communication rather than UI rendering.

  • Create request URLs.
  • Send HTTP requests.
  • Handle response status codes.
  • Decode JSON.
  • Convert JSON into models.
  • Throw meaningful exceptions.

96. UI Responsibilities

Widgets and screens should primarily focus on presenting state to the user.

  • Display loading indicators.
  • Display news articles.
  • Display error messages.
  • Handle user interaction.
  • Navigate between screens.
  • Trigger actions through state management or services.

97. News App Project Checklist

  • Flutter project created.
  • HTTP package added.
  • API provider selected.
  • API key configured safely.
  • News model created.
  • API service created.
  • GET request implemented.
  • JSON parsing implemented.
  • Home screen created.
  • News card created.
  • News detail screen created.
  • Category filtering implemented.
  • Search implemented.
  • Loading state implemented.
  • Error state implemented.
  • Empty state implemented.
  • Pull-to-refresh implemented.
  • Bookmarks implemented.
  • Responsive design implemented.
  • API errors handled.
  • Performance optimized.
  • Testing completed.

98. Skills You Learn From This Project

  • Flutter UI development.
  • Dart asynchronous programming.
  • REST API integration.
  • HTTP requests.
  • JSON parsing.
  • Dart model creation.
  • FutureBuilder.
  • State management.
  • Search functionality.
  • Category filtering.
  • Pagination.
  • Pull-to-refresh.
  • Error handling.
  • Loading state management.
  • Responsive Flutter layouts.
  • API security concepts.
  • Caching concepts.
  • Production application architecture.

99. Interview Questions Based on This Project

Question 1: What is an API?

An API is an interface that allows different software systems to communicate with each other. A Flutter application can use a web API to retrieve or send data.

Question 2: Why is the HTTP package used?

The HTTP package provides functionality for sending HTTP requests and receiving responses from web servers.

Question 3: Why is JSON commonly used by REST APIs?

JSON is lightweight, readable, and easily converted into Dart objects, making it convenient for transferring structured data between applications and servers.

Question 4: What is FutureBuilder?

FutureBuilder is a Flutter widget that builds its UI based on the current state of a Future, such as loading, success, or error.

Question 5: Why should API calls not be unnecessarily performed inside build()?

The build method can execute many times. Starting a new API request during every rebuild can result in unnecessary network traffic and poor performance.

Question 6: How do you handle API errors?

Check HTTP status codes, use try-catch for exceptions, display useful error states, and provide a retry mechanism when appropriate.

Question 7: How can you handle missing article images?

Check whether the image URL is empty or invalid and display a placeholder instead of assuming that every article contains a valid image.

Question 8: What is pagination?

Pagination divides a large dataset into smaller pages so the application can load data incrementally instead of requesting everything at once.

Question 9: How can API requests be reduced during search?

Debouncing can delay the search request until the user stops typing for a short period.

Question 10: Why should API keys be protected?

API keys can provide access to external services and may be subject to usage limits or billing. They should therefore be handled carefully and not unnecessarily exposed in public repositories.

Question 11: What is JSON parsing?

JSON parsing is the process of converting JSON data received from an API into structures that the Flutter application can work with, such as Dart maps and model objects.

Question 12: Why use a model class?

A model class gives API data a structured and type-safe representation, making the rest of the application easier to maintain.

100. Final Project Summary

The Flutter News App Using API project demonstrates how to build a real-world application that communicates with an external REST API. The application retrieves news data, parses JSON responses, converts the data into Dart models, and displays articles through reusable Flutter widgets.

The project also introduces category filtering, search, article details, bookmarks, refresh functionality, pagination, loading states, error handling, responsive layouts, caching concepts, and scalable application architecture.

101. Complete Project Flow

Start Application
      |
      v
Splash Screen
      |
      v
Home Screen
      |
      +---------------------+
      |                     |
      v                     v
Latest News             Categories
      |                     |
      |                     v
      |               Select Category
      |                     |
      +----------+----------+
                 |
                 v
            News Articles
                 |
        +--------+--------+
        |                 |
        v                 v
   Select Article      Search
        |                 |
        v                 v
 News Detail        Search Results
        |
   +----+----+
   |         |
   v         v
Bookmark   Share
   |
   v
Saved Articles

102. Conclusion

Building a Flutter News App Using API is an excellent project for learning how mobile applications communicate with external services. It teaches the complete process from making an HTTP request to displaying API data inside a responsive Flutter interface.

By completing this project, learners gain practical experience with REST APIs, HTTP requests, asynchronous programming, JSON parsing, Dart models, FutureBuilder, state management, search, filtering, pagination, error handling, caching, responsive UI, and scalable Flutter architecture.

The same API integration concepts can be applied to many other Flutter projects such as weather applications, e-commerce applications, sports applications, movie applications, finance applications, travel applications, and social media applications.

103. Learning Resources

For structured Flutter learning and additional practical training, explore the JustAcademy Flutter Training Course.

To register for a course demo, visit Register for Flutter Course Demo.


104. Final Learning Flow

Flutter Basics
      |
      v
Dart Async Programming
      |
      v
REST API Concepts
      |
      v
HTTP Requests
      |
      v
JSON Response
      |
      v
Dart Model
      |
      v
API Service
      |
      v
State Management
      |
      v
News UI
      |
      +----> Search
      |
      +----> Categories
      |
      +----> Bookmarks
      |
      +----> Pagination
      |
      +----> Refresh
      |
      +----> Error Handling
      |
      v
Complete Flutter News Application
Previous Next
whatsapp